home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / sprayOp.c < prev    next >
C/C++ Source or Header  |  1995-06-21  |  8KB  |  361 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/cursorfont.h>
  18. #include <X11/Xos.h>
  19. #include <sys/time.h>
  20. #include "xpaint.h"
  21. #include "Paint.h"
  22. #include <math.h>
  23. #include "misc.h"
  24.  
  25. #ifndef NOSTDHDRS
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #endif
  29.  
  30. typedef struct {
  31.     Widget        w;
  32.     int        useGauss;
  33.     int        x, y;
  34.     XtIntervalId    id;
  35.     Boolean        gcFlag, isTiled, trackDrawn, drawing;
  36.     int        lastX, lastY;
  37.     int        zoom;
  38.     /*
  39.     **  Borrowed from the info
  40.     */
  41.     GC        gc, gcx;
  42.     Pixmap        drawable;
  43.     Boolean        isFat;
  44. } LocalInfo;
  45.  
  46. static int    radius = 10, density = 10, radius2 = 10 * 10, rate = 100;
  47. static Boolean    style = True;
  48.  
  49. /*
  50. **  By default everything uses drand48(),
  51. **    I was making more exceptions than inclusinsion.
  52. */
  53. #define USE_DRAND
  54.  
  55. #if defined(SVR4) || defined(__osf__)
  56. #define SHORT_RANGE
  57. #else
  58. #ifndef random
  59. long    random(void);
  60. #endif
  61. #if !defined(sco)
  62. int    srandom(unsigned int);
  63. #endif
  64. #endif
  65.  
  66. #ifdef USE_DRAND
  67. # ifdef random
  68. #  undef random
  69. #  undef srandom
  70. # endif
  71. # define srandom    srand48
  72. # define RANDOM(s, f)    (drand48() * (f - s) + s)
  73. #else
  74. # ifdef SHORT_RANGE
  75. #  define RANGE        0x00000fff
  76. # else
  77. #  define RANGE        0x0fffffff
  78. # endif
  79. # define RANDOM(s, f)    (((double)(random() % RANGE) / (double)RANGE) * (f - s) + s)
  80. #endif
  81.  
  82. static void gauss(int range, int *x, int *y)
  83. {
  84.     float        fac, r, v1, v2;
  85.  
  86.     do {
  87.         v1 = RANDOM(-1.0, 1.0);
  88.         v2 = RANDOM(-1.0, 1.0);
  89.         r  = v1 * v1 + v2 * v2;
  90.     } while (r >= 1.0);
  91.  
  92.     fac = -2.0 * log(r) / r;
  93.     if (fac <= 0.0)
  94.         fac = 0.0;
  95.     else
  96.         fac = sqrt(fac) / 2.0;
  97.  
  98.     *x = (v1 * fac) * range;
  99.     *y = (v2 * fac) * range;
  100. }
  101.  
  102. static void draw(LocalInfo *l)
  103. {
  104.     int        i;
  105.     XRectangle    rect;
  106.     union {
  107.         XSegment    s[512];
  108.         XPoint        p[512];
  109.     } p;
  110.     
  111.     UndoGrow(l->w, l->x - radius, l->y - radius);
  112.     UndoGrow(l->w, l->x + radius, l->y + radius);
  113.  
  114.     for (i = 0; i < density; i++) {
  115.         int    rx, ry;
  116.  
  117.         do {
  118.             if (l->useGauss) {
  119.                 gauss(radius, &rx, &ry);
  120.             } else {
  121.                 rx = RANDOM(-radius, radius);
  122.                 ry = RANDOM(-radius, radius);
  123.             }
  124.         } while (rx * rx + ry * ry > radius2);
  125.  
  126.         if (l->isTiled) {
  127.             p.s[i].x1  = l->x + rx;
  128.             p.s[i].y1  = l->y + ry;
  129.             p.s[i].x2  = l->x + rx;
  130.             p.s[i].y2  = l->y + ry;
  131.         } else {
  132.             p.p[i].x   = l->x + rx;
  133.             p.p[i].y   = l->y + ry;
  134.         }
  135.     }
  136.  
  137.     XYtoRECT(l->x - radius, l->y - radius,
  138.          l->x + radius, l->y + radius, &rect);
  139.  
  140.     if (l->isTiled) {
  141.         XDrawSegments(XtDisplay(l->w), l->drawable, l->gc, p.s, density);
  142.         if (!l->isFat)
  143.             XDrawSegments(XtDisplay(l->w), XtWindow(l->w), l->gc, p.s, density);
  144.     } else {
  145.         XDrawPoints(XtDisplay(l->w), l->drawable, l->gc, p.p, density, CoordModeOrigin);
  146.         if (!l->isFat)
  147.             XDrawPoints(XtDisplay(l->w), XtWindow(l->w), l->gc, p.p, density, CoordModeOrigin);
  148.     }
  149.  
  150.     PwUpdate(l->w, &rect, False);
  151. }
  152.  
  153. static void drawEvent(LocalInfo *l)
  154. {
  155.     draw(l);
  156.     l->id = XtAppAddTimeOut(XtWidgetToApplicationContext(l->w), 
  157.                 rate, (XtTimerCallbackProc)drawEvent, (XtPointer)l);
  158. }
  159.  
  160. static void    drawOutline(Widget w, LocalInfo *l, int x, int y, Boolean flag)
  161. {
  162.     Display    *dpy   = XtDisplay(w);
  163.     Window    window = XtWindow(w);
  164.     XArc    arc;
  165.  
  166.     arc.width  = radius * l->zoom * 2;
  167.     arc.height = radius * l->zoom * 2;
  168.     arc.angle1 = 0;
  169.     arc.angle2 = 360 * 64;
  170.  
  171.     if (l->trackDrawn) {
  172.         arc.x = l->lastX - radius * l->zoom;
  173.         arc.y = l->lastY - radius * l->zoom;
  174.         XDrawArcs(dpy, window, l->gcx, &arc, 1);
  175.         l->trackDrawn = False;
  176.     }
  177.  
  178.     if (flag) {
  179.         arc.x = x - radius * l->zoom;
  180.         arc.y = y - radius * l->zoom;
  181.         XDrawArcs(dpy, window, l->gcx, &arc, 1);
  182.  
  183.         l->lastX = x;
  184.         l->lastY = y;
  185.         l->trackDrawn = True;
  186.     }
  187. }
  188.  
  189.  
  190. static void    press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
  191. {
  192.     GC    sgc;
  193.     int    width, rule, rule2;
  194.     /*
  195.     **  Check to make sure all buttons are up, before doing this
  196.     */
  197.     if ((event->state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)) != 0)
  198.         return;
  199.  
  200.     l->x = event->x;
  201.     l->y = event->y;
  202.  
  203.     l->useGauss = style;
  204.     l->drawing = True;
  205.     drawOutline(w, l, 0, 0, False);
  206.  
  207.     UndoStartPoint(w, info, event->x, event->y);
  208.  
  209.     l->drawable = info->drawable;
  210.     l->isFat    = info->isFat;
  211.  
  212.     XtVaGetValues(w, XtNlineWidth, &width, 
  213.              XtNfillRule, &rule, 
  214.              XtNlineFillRule, &rule2, 
  215.              NULL);
  216.     if (!l->gcFlag)
  217.         l->gcFlag = (width != 0);
  218.     
  219.     if (event->button == Button2) {
  220.         sgc = info->second_gc;
  221.         l->isTiled = (rule2 != FillSolid);
  222.     } else if (event->button == Button1) {
  223.         sgc = info->first_gc;
  224.         l->isTiled = (rule  != FillSolid);
  225.     } else
  226.         return;
  227.  
  228.     if (l->gcFlag) {
  229.         if (l->gc == None)
  230.             l->gc = XCreateGC(XtDisplay(w), info->drawable, 0, NULL);
  231.         XCopyGC(XtDisplay(w), sgc, ~GCLineWidth, l->gc);
  232.     } else {
  233.         l->gc       = sgc;
  234.     }
  235.  
  236.     if (l->id == (XtIntervalId)NULL)
  237.         drawEvent(l);
  238.     else
  239.         draw(l);
  240. }
  241.  
  242. static void    motion(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info) 
  243. {
  244.     if (l->drawing && info->surface == opPixmap) {
  245.         l->x = event->x;
  246.         l->y = event->y;
  247.  
  248.         draw(l);
  249.     } else if (!l->drawing && info->surface == opWindow) {
  250.         l->zoom = info->zoom;
  251.         drawOutline(w, l, event->x, event->y, True);
  252.     }
  253. }
  254.  
  255. static void    release(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
  256. {
  257.     int    mask;
  258.  
  259.     /*
  260.     **  Check to make sure all buttons are up, before doing this
  261.     */
  262.     mask = Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
  263.     switch (event->button) {
  264.     case Button1:    mask ^= Button1Mask; break;
  265.     case Button2:    mask ^= Button2Mask; break;
  266.     case Button3:    mask ^= Button3Mask; break;
  267.     case Button4:    mask ^= Button4Mask; break;
  268.     case Button5:    mask ^= Button5Mask; break;
  269.     }
  270.     if ((event->state & mask) != 0)
  271.         return;
  272.  
  273.     if (l->id != (XtIntervalId)NULL)
  274.         XtRemoveTimeOut(l->id);
  275.  
  276.     l->id = (XtIntervalId)NULL;
  277.     l->drawing = False;
  278. }
  279.  
  280. static void    leave(Widget w, LocalInfo *l, XEvent *event, OpInfo *info) 
  281. {
  282.     drawOutline(w, l, 0, 0, False);
  283. }
  284.  
  285.  
  286. /*
  287. **  Those public functions
  288. */
  289. void SpraySetParameters(int r, int d, int sp)
  290. {
  291.     radius = r;
  292.     radius2 = r * r;
  293.     density = d;
  294.     rate = sp * 10;
  295. }
  296. Boolean SprayGetStyle()
  297. {
  298.     return style;
  299. }
  300. void SpraySetStyle(Boolean flag)
  301. {
  302.     style = flag;
  303. }
  304.  
  305. static void *commonSprayAdd(Widget w, Boolean flag)
  306. {
  307.     LocalInfo    *l = XtNew(LocalInfo);
  308.     static int    inited = False;
  309.  
  310.     if (!inited) {
  311.         srandom((int)time(0));
  312.         inited = True;
  313.     }
  314.  
  315.     l->w   = w;
  316.     l->id  = (XtIntervalId)NULL;
  317.     l->gc  = None;
  318.     l->gcx = GetGCX(w);
  319.     l->gcFlag = False;
  320.     l->useGauss = flag;
  321.     l->trackDrawn = False;
  322.     l->drawing  = False;
  323.  
  324.     XtVaSetValues(w, XtNcompress, False,
  325.                      XtVaTypedArg, XtNcursor, XtRString, "spraycan", sizeof(Cursor), NULL);
  326.  
  327.     OpAddEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
  328.     OpAddEventHandler(w, opWindow|opPixmap, PointerMotionMask, FALSE, (OpEventProc)motion, l);
  329.     OpAddEventHandler(w, opPixmap, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
  330.     OpAddEventHandler(w, opWindow, LeaveWindowMask, FALSE, (OpEventProc)leave, l);
  331.  
  332.     return l;
  333. }
  334. void *SprayAdd(Widget w)
  335. {
  336.     return commonSprayAdd(w, style);
  337. }
  338. void SprayRemove(Widget w, LocalInfo *l)
  339. {
  340.     OpRemoveEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
  341.     OpRemoveEventHandler(w, opWindow|opPixmap, PointerMotionMask, FALSE, (OpEventProc)motion, l);
  342.     OpRemoveEventHandler(w, opPixmap, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
  343.     OpRemoveEventHandler(w, opWindow, LeaveWindowMask, FALSE, (OpEventProc)leave, l);
  344.  
  345.     if (l->gcFlag)
  346.         XFreeGC(XtDisplay(w), l->gc);
  347.     if (l->id != (XtIntervalId)NULL)
  348.         XtRemoveTimeOut(l->id);
  349.  
  350.     XtFree((XtPointer)l);
  351. }
  352.  
  353. void *SmearAdd(Widget w)
  354. {
  355.     return commonSprayAdd(w, False);
  356. }
  357. void SmearRemove(Widget w, LocalInfo *l)
  358. {
  359.     SprayRemove(w, l);
  360. }
  361.